
package Sintactico;

import java.util.ArrayList;
import Enumerados.*;
import Lexico.Token;

/**
 *
 * @author
 *
 * Almaraz Hernández, Jesús
 * Bécares García, Javier
 * Calzada Martínez, Jesús
 * Campos Cantero, Pablo
 * Gómez Galindo, Alejandro
 * Ortiz Sánchez, Enrique
 *
 *
 */


public class AnalizadorSintactico {

    private ArrayList tokens;
    private ArrayList codigo;
    private ArrayList errores;
    private tablaSimbolos ts;
    private boolean errorP;
    private int tokenActual;
    private int linea;
    private int columna;
    private static enum tipoAtributoS {ENT,REAL,LOG,TERR};
    //private StringBuffer tipoAS;

    public AnalizadorSintactico(ArrayList tokens){
        this.tokens=tokens;
        this.codigo=new ArrayList();
        this.errores=new ArrayList();
        this.ts= new tablaSimbolos();
        this.errorP=false;
        this.tokenActual=0;
        this.linea=1;
        this.columna=1;
        //this.tipoAS=new StringBuffer();
    }

    public ArrayList Inicio(){
        errorP=reconocePrograma();
        return codigo;
    }

    public String getErrores(){
          String s="";
            for(int i=0;i<errores.size();i++){
            s+=errores.get(i).toString()+"\n";
            }
            return s;
    }

    public ArrayList getVariables(){
        return ts.getVariables();
    }

    private boolean reconocePrograma() {
        boolean errorDec=false;
        boolean errorAcc=false;


        Decs(errorDec);
        if(!errorDec){
            errorAcc=reconoceAcciones();
            codigo.add("STOP\n");
        }
        return (errorDec || errorAcc);

    }
    private void Decs(boolean errDs){

        //La tabla de simbolos "se crea" en la constructora de la clase.
        //La direccion se inicializa en la constructora. 

        boolean errhRD=false;
        int dirhRD=-1;

        int dirRD=-1;
        boolean errRD=false;

        Token tokAux = (Token) tokens.get(tokenActual);
        Enumerados.categoriaLexica catAux = tokAux.getCat();

        if(catAux.equals(Enumerados.categoriaLexica.CLTENT) || catAux.equals(Enumerados.categoriaLexica.CLTREAL)){

            RDecs(dirhRD,errhRD,dirRD,errRD);
            errDs=errRD;
        }
        errDs=false;

    }
    private void RDecs(int dirhRD0, boolean errhRD0, int dirRD0, boolean errRD0){

        StringBuffer identificador=new StringBuffer("");
        String idD;
        //Enumerados.tipoIdentificador tipoD = null;
        StringBuffer tipoD=new StringBuffer("");

        Token tokAux1 = (Token) tokens.get(tokenActual+1);
        Enumerados.categoriaLexica catAux1 = tokAux1.getCat();
        columna++;

        if(catAux1.equals(Enumerados.categoriaLexica.CLIDENT)){

            Token tokAux2 = (Token) tokens.get(tokenActual+2);
            Enumerados.categoriaLexica catAux2 = tokAux2.getCat();
            columna++;

            if(catAux2.equals(Enumerados.categoriaLexica.CLPYC)){

                Dec(identificador,tipoD);
                idD=identificador.toString();
                String tipod=tipoD.toString();
                tipoIdentificador tipoId= tipoIdentificador.valueOf(tipod);
                int dirhRD1=dirhRD0+1;
                this.ts.setIdentificador(idD, dirhRD0 + 1, tipoId);
                //boolean pepe=ts.estaID(idD);
                boolean errhRD1= (errhRD0 || ts.estaID(idD));

                errores.add("Error en la linea "+linea+" y columna "+columna+" porque la variable "+idD+" ya ha sido declarada con anterioridad");
                //MIRAR


                siguienteToken();
                linea++;
                columna=1;

                Token tokAux = (Token) tokens.get(tokenActual);
                Enumerados.categoriaLexica catAux = tokAux.getCat();

                if(catAux.equals(Enumerados.categoriaLexica.CLTENT) || catAux.equals(Enumerados.categoriaLexica.CLTREAL)){

                    int dirRD1=-1;
                    boolean errRD1=false;

                    RDecs(dirhRD1,errhRD1,dirRD1, errRD1);

                    dirRD0=dirRD1;
                    errRD0=errRD1;

                }
                else{
                    //HA TERMINADO DE RECONOCER DELCARACIONES
                    dirRD0=dirhRD0; //Supongo que devolvemos la misma dir que nos entro
                    errRD0=errhRD1; //no devolvemos true porque no se ha producido ningun error. Simplente no coinciden
                                    //los tokens y por tanto puede ser que hayamos pasado a la seccion de acciones.
                                    //Supuestamente es true si existe ya el identificador reconocido.
                }

            }
            else{
            //METER UN ERROR DICIENDO QUE ESPERABAMOS UN TOKEN DE TIPO PYC
                errores.add("Error en la linea "+linea+" y columna "+columna+" porque hemos encontrado un token de tipo "+tokAux2.getLex()+" cuando esperabamos un token de tipo ;");
                dirRD0=dirhRD0;
                errRD0=true;
            }
        }
        else{
        //METER ERROR DICIENDO QUE ESPERABAMOS UN TOKEN DE TIPO IDENT
            errores.add("Error en la linea "+linea+" y columna "+columna+" porque hemos encontrado un token de tipo "+tokAux1.getLex()+" cuando esperabamos un token de tipo IDENT");
            dirRD0=dirhRD0;
            errRD0=true;
        }
    }
    private void Dec(StringBuffer idD, StringBuffer tipoD){
        Token tokAux = (Token) tokens.get(tokenActual);
        Enumerados.categoriaLexica catAux = tokAux.getCat();

        if(catAux.equals(Enumerados.categoriaLexica.CLTENT))
            //tipoD=Enumerados.tipoIdentificador.ENT;
            tipoD.append(Enumerados.tipoIdentificador.ENT.toString());
        else
            //tipoD=Enumerados.tipoIdentificador.REAL;
            tipoD.append(Enumerados.tipoIdentificador.REAL.toString());

        siguienteToken();

        tokAux = (Token) tokens.get(tokenActual);
        idD.append(tokAux.getLex());

        siguienteToken();
    }

/*******************************************************************************
 *                                                                             *
 *  ACCIONES                                                                   *
 *                                                                             *
 *      Accs  ::= Acc RAccs                                                    *
 *      RAccs ::= Acc RAccs | λ                                                *
 *                                                                             *
 ******************************************************************************/

    private boolean reconoceAcciones(){
        boolean errAcc;
        boolean errRA=false;
        StringBuffer tipoAcc=new StringBuffer("");
  
/*      Reconocemos la primera accion.                                        */
        errAcc=reconoceAcc(tipoAcc);

/*      Pedimos el siguiente token para comprobar si es final de fichero.     */
        Token actual=dameTokenActual();

/*      Seguimos procesando las acciones en el caso de que no se haya producido
        ningun error en la primera accion y no hemos llegado a final de fichero.
        Es decir, tenemos otra accion que reconocer.                          */
        if(!errAcc){
            if(!actual.getCat().equals(Enumerados.categoriaLexica.CLEOF)){
/*              Reconocemos o procesamos el resto de acciones.                */
                errRA=reconoceRAccs();
            }
        }
/*      Hemos terminado de reconocer todas las acciones. Devolvemos la
        posibilidad de que se haya podido producir algun error en el resto de
        acciones, en la primera accion o que se haya producido un error de
        tipos.                                                                */
        return (errAcc || errRA || tipoAcc.toString().equals(Enumerados.tipoIdentificador.TERR.toString()));
    }
/*  Metodo semejante al anterior. Obviamos los comentarios.                   */
    private boolean reconoceRAccs(){
        boolean errAcc;
        boolean errRA=false;
        StringBuffer tipoAcc=new StringBuffer("");

        errAcc = reconoceAcc(tipoAcc);

        Token actual=dameTokenActual();

        if(!errAcc){
            if(!actual.getCat().equals(Enumerados.categoriaLexica.CLEOF)){

                    errRA = reconoceRAccs();
            }
        }
        return (errAcc || errRA || tipoAcc.toString().equals(Enumerados.tipoIdentificador.TERR.toString()));
    }

/*******************************************************************************
 *                                                                             *
 *  ACCION                                                                     *
 *                                                                             *
 *      Acc ::= Exp ;                                                          *
 *                                                                             *
 *  Hay que contar con que Exp puede ir entre parentesis. Estos se procesan en *
 *  EXPRESION ya que es aqui donde existira la recursiond Fact y donde se      *
 *  trataran los parentesis de forma general.                                  *
 *                                                                             *
 ******************************************************************************/

    private boolean reconoceAcc(StringBuffer tipohRA){
        StringBuffer tipoExp=new StringBuffer("");
        boolean errExp=false;
/*      Reconocemos o procesamos la expresion                                 */
        errExp=reconoceExp(tipoExp);
/*      Si no se ha producido ningun error comprobamos el siguiente token. Este
        tiene que ser un ; sino devolvemos un error.                          */
        if(!errExp){
            Token actual=dameTokenActual();
/*          Comprobamos que no nos llegue del analizador lexico un token
            erroneo. Si es asi, tendremos que encontrar el final de esta accion
            para procesar la siguiente o el final de fichero para terminar    */
            if(actual.getCat().equals(Enumerados.categoriaLexica.CLERROR)){
/*              Buscamos el ; o el final de fichero para pasar a procesar la
                siguiente accion. Indicamos el error correspondiente          */
                errores.add("Token en la linea "+linea+" y columna "+columna+" erroneo. Token desconocido");
                while(!actual.getCat().equals(Enumerados.categoriaLexica.CLPYC)
                        || !actual.getCat().equals(Enumerados.categoriaLexica.CLEOF)){
                    siguienteToken();
                    actual=dameTokenActual();
                }
            }
/*          El siguiente token que debemos reconocer debe ser un ;            */
            if (!actual.getCat().equals(Enumerados.categoriaLexica.CLPYC)){

                errores.add("No encontrado el token ; al final de la linea "+linea);
                return true;
            }
/*          Si se ha reconocido el ; se termina de procesar la accion y se
            avanza el token para dejar preparada la siguiente accion y se
            devuelven los correspondientes errores ademas de actualizar las
            variables de linea y columna para el control de errores.          */
            siguienteToken();
            tipohRA.append(tipoExp);
            linea++;
            columna=1;
        }
        return errExp;

    }
/*******************************************************************************
 *                                                                             *
 *  EXPRESION                                                                  *
 *                                                                             *
 *      Exp ::= IEXP | IIf | IWhile                                            *
 *                                                                             *
 *  Recordemos que las expresiones pueden ir precedidas por parentesis y que de*
 *  ser asi tenemos que tenerlos en cuenta a la hora de procesar la expresion. *
 *                                                                             *
 ******************************************************************************/

    private boolean reconoceExp(StringBuffer tipoExp){
        boolean parentesis=false;
        boolean errIExp=false;
        boolean errIf=false;
        boolean errWhile=false;

        Token actual=dameTokenActual();
                             
        if (actual.getCat().equals(Enumerados.categoriaLexica.CLIF)){
            StringBuffer tipoIf = new StringBuffer("");
            //errIf=reconoceIf(tipoIf);
            tipoExp.append(tipoIf);   
        }
        else if (actual.getCat().equals(Enumerados.categoriaLexica.CLWHILE)){
            StringBuffer tipoWhile = new StringBuffer("");
            //errWhile=reconoceWhile(tipoWhile);
            tipoExp.append(tipoWhile);
        }
        else{
            StringBuffer tipoIExp = new StringBuffer("");
            errIExp=reconoceIExp(tipoIExp);
            tipoExp.append(tipoIExp);
        }
        return (errIf||errWhile||errIExp);
}
/*******************************************************************************
 *                                                                             *
 *  IEXPRESION                                                                 *
 *                                                                             *
 *      IExp ::= IN IDENT | OUT IAsig | IAsig                                  *
 *                                                                             *
 *                                                                             *
 ******************************************************************************/
    private boolean reconoceIExp(StringBuffer tipoIExp){
        boolean errIAsig=false;

        Token actual=dameTokenActual();
        
/*******************************      IN       ********************************/
            
        if (actual.getCat().equals(Enumerados.categoriaLexica.CLIN)){
            siguienteToken();
            actual=dameTokenActual();
/*          Si es de tipo IN, comprobamos que el siguiente token sea de
            tipo IDENT. Sino, devolvemos un error de tipo.                */
            if (!actual.getCat().equals(Enumerados.categoriaLexica.CLIDENT)){
                tipoIExp.append("TERR");
                errores.add("Token incorrecto en la linea "+linea+" y columna "+columna+". Se esperaba un token de tipo IDENTIFICADOR.");
                return true;
            }
            else{
             /* Comprobamos que el identificador que acabamos de leer haya
                sido declarado previamente en la seccion de declaraciones.
                Para ello, cogemos el lexema del identificador (es decir,
                del token actual) y lo buscamos en la tabla de simbolos que
                heredamos de Exp. */
                if(ts.estaID(actual.getLex())){
                     /* Generamos el codigo apropiado para la que la maquina
                        p ejecute el programa correctamente. Devolvemos tb
                        el tipo de expresion que acabamos de procesar para
                        controlar posibles errores de tipo. */
                        codigo.add("in " + ts.getTipo(actual.getLex())+ "\n" );
                        codigo.add("desapila_dir " + ts.getDir(actual.getLex())+ "\n");
                        tipoIExp.append((ts.getTipo(actual.getLex())).toString());
                }
                else{
                 /* Si no esta el identificador registramos el error tanto
                    en el array de errores como en el tipo de la expresion.
                    No devolvemos true ya que este es un error contextual
                    que no para la ejecucion del analizador sintatico. */
                    errores.add("Error sintactico contextual en la linea "+linea +" y columna "+columna+". La variable "+actual.getLex()+ " no ha sido declarado previamente");
                    tipoIExp.append("TERR");
                    siguienteToken();
                    return false;
                }
            }
            siguienteToken();
        }
/*******************************      IN       ********************************/

/*******************************      OUT      ********************************/

        else if (actual.getCat().equals(Enumerados.categoriaLexica.CLOUT)){
               StringBuffer tipoIAsig=new StringBuffer("");

               /* Si hemos reconocido el token OUT, avanzamos el token
               actual y pasamos a reconocer la ExpBasica.*/
               siguienteToken();
             
               errIAsig=reconoceIAsig(tipoIAsig);
               tipoIExp.append(tipoIAsig);
               codigo.add("out\n");
        }
/*******************************      OUT      ********************************/

/******************************      IAsig      *******************************/

        /*Segun la gramatica pasariamos a reconoceIAsig de todas todas, pero en
         la implementacion tenemos que distinguir cuando pasamos a reconoceIAsig
         porque tenemos una instruccion de asignacion verdaderamente, es decir,
         nos llega un IDENT y cuando pasamos a reconoceIAsig porque no hemos
         encontrado ninguna instruccion que "sepamos" ejecutar. En este ultimo
         caso simplemente terminamos el metodo reconoceIExp y no reconocemos esa
         linea porque no es una expresion valida. De esta forma, pueden compilar
         programas como 2; sin que de error. Pero no hace nada, claro esta.*/
        else if (actual.getCat().equals(Enumerados.categoriaLexica.CLIDENT)){
            StringBuffer tipoIAsig = new StringBuffer("");
            errIAsig=reconoceIAsig(tipoIAsig);
            tipoIExp.append(tipoIAsig);
        }
        return errIAsig;
 }

/*******************************************************************************
 *                                                                             *
 *  IAsig                                                                      *
 *                                                                             *
 *      IAsig ::= IDENT=IAsig | ExpBasica                                      *
 *                                                                             *
 *                                                                             *
 ******************************************************************************/

    private boolean reconoceIAsig(StringBuffer tipoIAsig){
        boolean apilar=false;
        boolean errIAsig=false;
        boolean errExpBasica=false;

        Token actual=dameTokenActual();
        Token siguienteActual=(Token) tokens.get(tokenActual+1);
        
        if ((actual.getCat().equals(Enumerados.categoriaLexica.CLIDENT))
            && (siguienteActual.getCat().equals(Enumerados.categoriaLexica.CLASIG))){
            /* Comprobamos que el identificador haya sido declarado en la
             seccion de declaraciones. Para ello, comprobamos que exista
             dicho simbolo en la tabla de simbolos. Sino, procesamos el
             error. De momento no devolvemos true a la espera de procesar
             el resto de la expresion. */
            if (!ts.estaID(actual.getLex())){
                    errores.add("Error sintactico contextual en la linea "+linea +" y columna "+columna+". La variable "+actual.getLex()+ " no ha sido declarado previamente");
                    tipoIAsig.append("TERR");
                    errIAsig=false;
            }
            else{
                /* Cogemos el lexema del identificador actual antes de avanzar
                 el token. */
                String ident=actual.getLex();
                /* Comprobamos si esta expresion de asignacion es el factor o
                 expresion a asignar de una expresion anterior.
                 De ser asi, debemos apilar el valor de dicha expresion despues
                 procesarla. */
                Token anteriorActual=(Token) tokens.get(tokenActual-1);
                if ((anteriorActual.getCat().equals(Enumerados.categoriaLexica.CLASIG))
                    || (anteriorActual.getCat().equals(Enumerados.categoriaLexica.CLOUT)))
                    apilar=true;                

                siguienteToken();
                actual=dameTokenActual();
                /* Comprobamos que el siguiente token leido sea el = . Sino,
                 procesamos el correspondiente error. */
                if (!actual.getCat().equals(Enumerados.categoriaLexica.CLASIG)){
                    errores.add("Error sintactico incontextual en la linea "+linea +" y columna "+columna+". Se esperaba un token de tipo asignacion (=)");
                    tipoIAsig.append("TERR");
                    errIAsig=true;
                }
                else{
                    /* Pedimos el siguiente token a procesar. */
                    siguienteToken();
                    actual=dameTokenActual();
                    /* Pasamos a reconocer ExpBasica. Recogemos el tipo de la
                    expresion y el codigo que se genera para la maquina p en los
                    argumentos que le pasamos. La funcion nos devuelve si ha
                    encontrado algun error en el procesamiento. */
                    StringBuffer tipoIAsig1=new StringBuffer("");
                    errIAsig=reconoceIAsig(tipoIAsig1);
                    /* Comprobamos el tipo final que tiene que tener la expresion
                     de asignacion */
                    if ((ts.getTipo(ident).toString().equals("REAL"))
                    &&((tipoIAsig1.toString().equals("REAL"))
                            ||(tipoIAsig1.toString().equals("ENT")))){
                        
                        if (tipoIAsig1.toString().equals("ENT"))
                            codigo.add("CASTING_R"+"\n");

                        tipoIAsig.append("REAL");
                    }
                    else if((ts.getTipo(ident).toString().equals("ENT"))
                    &&(tipoIAsig1.toString().equals("ENT"))){

                        tipoIAsig.append("ENT");
                    }
                    else if((ts.getTipo(ident).toString().equals("LOG"))
                    &&(tipoIAsig1.toString().equals("LOG"))){

                        tipoIAsig.append("LOG");
                    }
                    else{
                        errores.add("Error sintactico contextual en la linea "+linea +" y columna "+columna+". El tipo del simbolo y el tipo de la expresion que se le asignará son incompatibles.");
                        tipoIAsig.append("TERR");
                        errIAsig=true;
                        
                    }
                    codigo.add("desapila_dir "+ ts.getDir(ident)+ "\n");
                    if (apilar)
                        codigo.add("apila_dir "+ ts.getDir(ident)+ "\n");
                }
            }
        }
        else{
            StringBuffer tipoExpBasica=new StringBuffer("");
            /* Pasamos a reconocer ExpBasica. Recogemos el tipo de la
            expresion y el codigo que se genera para la maquina p en los
            argumentos que le pasamos. La funcion nos devuelve si ha
            encontrado algun error en el procesamiento. */
            errExpBasica=reconoceExpBasica(tipoExpBasica);

            errIAsig=errExpBasica;
   
            tipoIAsig.append(tipoExpBasica);
        }
        return errIAsig;
}

/*******************************************************************************
 *                                                                             *
 * EXPRESION BASICA                                                            *
 *                                                                             *
 *      ExpBasica  ::= ExpSum FExpBasica                                       *
 *      FExpBasica ::= OpOrd ExpSum | λ                                        *
 *                                                                             *
 ******************************************************************************/
    private boolean reconoceExpBasica(StringBuffer tipoExpBasica){
        boolean errhFE, errEB;
        boolean errExpSum=false;
        boolean errFE=false;
        StringBuffer tipoExpSum=new StringBuffer("");

        /* Comenzamos la recursion de la gramatica. El primer paso es comprobar
         si se trata de una exprsion de suma. Esta funcion, devolvera si se ha
         producido un error a lo largo de la recursion de procesar la expresion.
         Recordad que no devuelve si es una expresion de suma.*/
        errExpSum = reconoceExpSum(tipoExpSum);
        /*A pesar de la posibilidad de producirse un error en el reconocimiento
         o procesamiento de la expresion de suma anterior, seguimos analizando
         esta expresion basica para detectar mas errores. Es en el analisis de
         la segunda parte de la expresion donde finalmente devolveremos si se
         ha producido algun error durante el procesamiento de toda la expresion
         basica.*/
        errhFE = errExpSum;
        /* Preparamos el tipo de la expresion "suma" que acaba de ser procesado
         para comprobar que concuerde con la segunda parte de la expresion
         (alineamiento de tipos).*/
        StringBuffer tipohFExp=new StringBuffer("");
        tipohFExp.append(tipoExpSum);
        StringBuffer tipoFExp=new StringBuffer("");
        /*Procesamos la segunda parte de la expresion basica.*/
        errFE = reconoceFExp(errhFE,tipohFExp,tipoFExp);
        /*Devolveremos que hemos encontrado un error en expresion basica si se
         ha producido un error en el reconocimiento de la segunda parte de esta
         expresion basica.*/
        errEB = errFE;
        /* El tipo final de la expresion basica sera el tipo que nos devuelve el
         procesamiento de la segunda parte de la expresion basica.*/
        tipoExpBasica.append(tipoFExp);
        return errEB;

    }

    private boolean reconoceFExp(boolean errhFE, StringBuffer tipohFE, StringBuffer tipoFExp){
        boolean errFE=false;
        Token actual=dameTokenActual();
        /* Comprobamos si realmente se trata de una operacion de orden. Para
         ello, el token actual tendria que ser alguno de los operadores de orden
         siguientes. Si no es uno de ellos, es porque en la recursion de la
         primera parte de la expresion, se ha procesado la expresion entera como
         otro tipo de expresion y por tanto no es una expresion de orden.*/
        if ((actual.getCat().equals(Enumerados.categoriaLexica.CLMAY))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLMAYIG))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLMEN))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLMENIG))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLCOMP))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLDIST))){

            String operador;
            boolean errExpSum=false;

            /*Recogemos el operador*/
            operador = reconoceOpOrd(actual);
            siguienteToken();
            /*Comenzamos el procesamiento de la segunda parte de la
             expresion. Al igual que la primera parte, este procesamiento es
             recursivo ya que esta segunda parte puede ser una expresion
             basica completa.*/
            StringBuffer tipoExpSum=new StringBuffer("");
            errExpSum = reconoceExpSum(tipoExpSum);
            /* Añadimos el codigo necesario del operador para que nuestra
             maquina p procese la operacion entre las dos partes de la expresion
             basica correctamente.*/
            codigo.add(operador + "\n");
            /* Copiamos la posibilidad de haber encontrado un error durante el
             procesamiento de las dos partes de la expresion basica.*/
            errFE=(errhFE||errExpSum);
            /* Nos falta devolver el tipo final de la expresion basica. Para
             ello, tendremos que comprobar los distintos tipos de las dos partes
             procesadas.*/
            if ((tipohFE.toString().equals(tipoAtributoS.REAL.toString()))
                    &&(tipoExpSum.toString().equals(tipoAtributoS.REAL.toString()))){

                    tipoFExp.append(tipoAtributoS.LOG.toString());
            }
            else if ((tipohFE.toString().equals(tipoAtributoS.REAL.toString()))
                    &&(tipoExpSum.toString().equals(tipoAtributoS.ENT.toString()))){

                    tipoFExp.append(tipoAtributoS.LOG.toString());
            }
            else if ((tipohFE.toString().equals(tipoAtributoS.ENT.toString()))
                    &&(tipoExpSum.toString().equals(tipoAtributoS.REAL.toString()))){

                    tipoFExp.append(tipoAtributoS.LOG.toString());
            }
            else if ((tipohFE.toString().equals(tipoAtributoS.ENT.toString()))
                    &&(tipoExpSum.toString().equals(tipoAtributoS.ENT.toString()))){

                    tipoFExp.append(tipoAtributoS.LOG.toString());
            }
            else if ((tipohFE.toString().equals(tipoAtributoS.LOG.toString()))
                    &&(tipoExpSum.toString().equals(tipoAtributoS.LOG.toString()))){
                        if(operador.equals(categoriaLexica.CLCOMP.toString()) || operador.equals(categoriaLexica.CLDIST.toString())){

                           tipoFExp.append(tipoAtributoS.LOG.toString());
                        }
                        else{
                            /* Si no es un operador que admita dos operandos de
                             tipo logico añadimos un error y devolvemos el tipo
                             error (lo hacemos asi porque no se detiene el
                             procesamiento del programa)*/
                            errores.add("Error de operador no valido en la linea "+linea+" y columna "+columna+" para las expresiones logicas");
                            tipoFExp.append(tipoAtributoS.TERR.toString());
                        }
            }
            else{
                /* Añadimos un error y devolvemos tipo error (lo hacemos asi
                 porque no se detiene el procesamiento del programa) si la
                 combinacion de los tipos de los operandos no es valida para
                 este tipo de operador.*/
                if ((!tipohFE.toString().equals(tipoAtributoS.TERR.toString()))&&(!tipoExpSum.toString().equals(tipoAtributoS.TERR.toString()))){
                    errores.add("Error de tipos en la linea "+linea+" y en la columna "+columna);
                }
                tipoFExp.append(tipoAtributoS.TERR.toString());
            }
        }
        else{
            /* No es una expresion de orden y por tanto el tipo final de la
             expresion es el tipo que heredamos del procesamiento de la primera
             parte.*/
            tipoFExp.append(tipohFE);
        }
        return errFE;

    }

    private String reconoceOpOrd(Token actual){
       String operador="";
       if((actual.getCat().toString()).equals(categoriaLexica.CLMAY.toString()))
           operador="MA";
       if((actual.getCat().toString()).equals(categoriaLexica.CLMAYIG.toString()))
            operador="MAI";
       if((actual.getCat().toString()).equals(categoriaLexica.CLMEN.toString()))
            operador="ME";
       if((actual.getCat().toString()).equals(categoriaLexica.CLMENIG.toString()))
            operador="MEI";
       if((actual.getCat().toString()).equals(categoriaLexica.CLCOMP.toString()))
            operador="IG";
       if((actual.getCat().toString()).equals(categoriaLexica.CLDIST.toString()))
            operador="NIG";
      return operador;
    }

/*******************************************************************************
 *                                                                             *
 * EXPRESION SUMA                                                              *
 *                                                                             *
 *      ExpSum  ::= ExpMult RExpSum                                            *
 *      RExpSum ::= OpSum ExpMult RExpSum | λ                                  *
 *                                                                             *
 ******************************************************************************/
    private boolean reconoceExpSum(StringBuffer tipoExpSum){
        StringBuffer tipoExpMult= new StringBuffer("");
        StringBuffer tipohEM;
        boolean errhEM, errRES;
        /*Continuamos la recursion para reconocer la expresion. */
        boolean errEM = reconoceExpMult(tipoExpMult);
        
        errhEM =errEM;
        tipohEM=tipoExpMult;
        StringBuffer tipoRExpSum= new StringBuffer("");
        /*Reconocemos el resto de la expresion de suma.*/
        errRES= reconoceRExpSum(errhEM,tipohEM,tipoRExpSum);
        /*El tipo final de la expresion sera el que nos devuelve la funcion que
         procesa el resto de la expresion de suma.*/
        tipoExpSum.append(tipoRExpSum);
        return errRES;
    }

    private boolean reconoceRExpSum(boolean errhES, StringBuffer tipohES, StringBuffer tipoRES){
        boolean errhRES=false;
        Token actual=dameTokenActual();
        /* Comprobamos si realmente se trata de una operacion de "suma". Para
         ello, el token actual tendria que ser alguno de los operadores de
         "suma" siguientes. Si no es uno de ellos, es porque en la recursion de
         la primera parte de la expresion, se ha procesado la expresion entera
         como otro tipo de expresion y por tanto no es una expresion de "suma".*/
        if ((actual.getCat().equals(Enumerados.categoriaLexica.CLSUM))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLRES))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLOR))){
                /*Reconocemos el operador de la expresion*/
                String operador= reconoceOpSum(actual);
                siguienteToken();
                /*Comenzamos el procesamiento de la segunda parte de la
                expresion. Al igual que la primera parte, este procesamiento es
                recursivo ya que esta segunda parte puede ser una expresion
                basica completa.*/
                StringBuffer tipoExpMult=new StringBuffer("");
                boolean errEM = reconoceExpMult(tipoExpMult);
                /* Añadimos el codigo necesario del operador para que nuestra
                maquina p procese la operacion entre las dos partes de la
                expresion basica correctamente.*/
                codigo.add(operador + "\n");
                /*Devolvemos la posibilidad de error o en el procesamiento de la
                 primera parte de la expresion o en la segunda parte.*/
                errhRES=(errhES || errEM);
                /*Calculamos el tipo de la expresion completa a devolver.*/
                StringBuffer tipohRES = new StringBuffer("");
                /*Si los operadores son de suma o resta, comprobamos los tipos
                 de los operandos para calcular el tipo de la expresion final.*/
                if((actual.getCat().toString()).equals(categoriaLexica.CLSUM.toString())
                    || ((actual.getCat().toString()).equals(categoriaLexica.CLRES.toString()))){
                        if ((tipohES.toString().equals(tipoAtributoS.REAL.toString()))
                                &&(tipoExpMult.toString().equals(tipoAtributoS.REAL.toString()))){

                                tipohRES.append(tipoAtributoS.REAL.toString());
                        }
                        else if ((tipohES.toString().equals(tipoAtributoS.REAL.toString()))
                                &&(tipoExpMult.toString().equals(tipoAtributoS.ENT.toString()))){

                                tipohRES.append(tipoAtributoS.REAL.toString());
                        }
                         else if ((tipohES.toString().equals(tipoAtributoS.ENT.toString()))
                                &&(tipoExpMult.toString().equals(tipoAtributoS.REAL.toString()))){

                                tipohRES.append(tipoAtributoS.REAL.toString());
                        }
                         else if ((tipohES.toString().equals(tipoAtributoS.ENT.toString()))
                                &&(tipoExpMult.toString().equals(tipoAtributoS.ENT.toString()))){

                                tipohRES.append(tipoAtributoS.ENT.toString());
                        }
                         else{
                            /*Si los tipos de los operandos no cuadran con
                             ninguna de las combinacion correctas posibles,
                             apuntamos el error y decimos que el tipo final de
                             la expresion es de tipo error.*/
                            if ((!tipohES.toString().equals(tipoAtributoS.TERR.toString())) && (!tipoExpMult.toString().equals(tipoAtributoS.TERR.toString()))){
                                errores.add("Error de tipos en la linea "+linea+" y en la columna "+columna);
                            }
                            tipohRES.append(tipoAtributoS.TERR.toString());
                         }
                }
                /*Si el operando de la expresion es de tipo logico.*/
                else if ((actual.getCat().toString()).equals(categoriaLexica.CLOR.toString())){
                        if ((tipohES.toString().equals(tipoAtributoS.LOG.toString()))
                                &&(tipoExpMult.toString().equals(tipoAtributoS.LOG.toString()))){

                                tipohRES.append(tipoAtributoS.LOG.toString());
                        }
                        else{
                            /*Si los tipos de los operandos no cuadran con
                             ninguna de las combinacion correctas posibles,
                             apuntamos el error y decimos que el tipo final de
                             la expresion es de tipo error.*/
                            if ((!tipohES.toString().equals(tipoAtributoS.TERR.toString())) &&(!tipoExpMult.toString().equals(tipoAtributoS.TERR.toString()))){
                                errores.add("Error de operador no vÃ¡lido en la linea "+linea+" y columna "+columna+" porque las dos expresiones deben ser logicas");
                            }
                            tipohRES.append(tipoAtributoS.TERR.toString());
                        }
                }
                /*Si el operador no fuera ninguo de los operadores validos.*/
                else {
                        tipohRES.append(tipoAtributoS.TERR.toString());
                }
                /*Aqui como marca la produccion de la gramatica puesta en la
                 cabecera de la funcion, necesitamos llamar recursivamente de
                 nuevo a reconoceRExpSum por si esta expresion de suma estuviera
                 formada por mas de dos operandos y mas de un operador. Si no
                 fuera asi, no pasa nada porque la recursion de la expresion nos
                 devolvera el mismo tipo obtenido hasta ahora y lo mismo con el
                 error.*/
                StringBuffer tipoRES1=new StringBuffer("");
                boolean errRES1 = reconoceRExpSum(errhRES,tipohRES,tipoRES1);
                /*Preparamos tanto el tipo como el error a devolver.*/
                tipoRES.append(tipoRES1);
                return errRES1;
          }
        else{
            /*Si el resto de la expresion no es de tipo suma (porque el token
             actual no es de OpSum) es porque en la recursion de la primera
             parte de la expresion ya se ha reconocido la expresion basica
             entera.*/
            tipoRES.append(tipohES);
            return errhRES;
        }
    }

   private String reconoceOpSum(Token actual){
       String operador="";
       if((actual.getCat().toString()).equals(categoriaLexica.CLSUM.toString()))
           operador="ADD";
       if((actual.getCat().toString()).equals(categoriaLexica.CLRES.toString()))
            operador="SUB";
       if((actual.getCat().toString()).equals(categoriaLexica.CLOR.toString()))
            operador="OR";
      return operador;
    }
/*******************************************************************************
 *                                                                             *
 * EXPRESION MULTIPLICACION                                                    *
 *                                                                             *
 *      ExpMult  ::= ExpUn RExpMult                                            *
 *      RExpMult ::= OpMult ExpUn RExpMult | λ                                 *
 *                                                                             *
 ******************************************************************************/
    private boolean reconoceExpMult(StringBuffer tipoExpMult){
        StringBuffer tipoExpUn=new StringBuffer("");
        StringBuffer tipohExpUn;
        boolean errExpUn,errREM=false;
        boolean errhExpUn;

        /*Continuamos la recursion para reconocer la expresion. */
        errExpUn= reconoceExpUn(tipoExpUn);

        errhExpUn=errExpUn;
        tipohExpUn = tipoExpUn;
        StringBuffer tipoRExpUn=new StringBuffer("");
        /*Reconocemos el resto de la expresion de multiplicacion.*/
        errREM = reconoceRExpMult(errhExpUn,tipohExpUn,tipoRExpUn);
        /*El tipo final de la expresion sera el que nos devuelve la funcion que
         procesa el resto de la expresion de multiplicacion.*/
        tipoExpMult.append(tipoRExpUn);
        return errREM;
    }
    private boolean reconoceRExpMult(boolean errhEM, StringBuffer tipohEM, StringBuffer tipoREM){
        boolean errhREM=false;
        Token actual=dameTokenActual();
        /* Comprobamos si realmente se trata de una operacion de multiplicacion.
         Para ello, el token actual tendria que ser alguno de los operadores de
         multiplicacion siguientes. Si no es uno de ellos, es porque en la
         recursion de la primera parte de la expresion, se ha procesado la
         expresion entera como otro tipo de expresion y por tanto no es una
         expresion de multiplicacion.*/
        if ((actual.getCat().equals(Enumerados.categoriaLexica.CLDIV))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLMULT))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLAND))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLMOD))){
                /*Reconocemos el operador de la expresion*/
                String operador= reconoceOpMult(actual);
                siguienteToken();
                /*Comenzamos el procesamiento de la segunda parte de la
                expresion. Al igual que la primera parte, este procesamiento es
                recursivo ya que esta segunda parte puede ser una expresion
                basica completa.*/
                StringBuffer tipoExpUn=new StringBuffer("");
                boolean errEU = reconoceExpUn(tipoExpUn);
                /* Añadimos el codigo necesario del operador para que nuestra
                maquina p procese la operacion entre las dos partes de la
                expresion basica correctamente.*/
                codigo.add(operador + " \n");
                /*Devolvemos la posibilidad de error o en el procesamiento de la
                 primera parte de la expresion o en la segunda parte.*/
                errhREM=(errhEM || errEU);
                /*Calculamos el tipo de la expresion completa a devolver.*/
                StringBuffer tipohREM = new StringBuffer("");
                /*Si los operadores son de multiplicacion o division,
                 comprobamos los tipos de los operandos para calcular el tipo de
                 la expresion final.*/
                if((actual.getCat().toString()).equals(categoriaLexica.CLMULT.toString())
                    || ((actual.getCat().toString()).equals(categoriaLexica.CLDIV.toString()))){
                        if ((tipohEM.toString().equals(tipoAtributoS.REAL.toString()))
                                &&(tipoExpUn.toString().equals(tipoAtributoS.REAL.toString()))){

                                tipohREM.append(tipoAtributoS.REAL.toString());
                        }
                        else if ((tipohEM.toString().equals(tipoAtributoS.REAL.toString()))
                                &&(tipoExpUn.toString().equals(tipoAtributoS.ENT.toString()))){

                                tipohREM.append(tipoAtributoS.REAL.toString());
                        }
                         else if ((tipohEM.toString().equals(tipoAtributoS.ENT.toString()))
                                &&(tipoExpUn.toString().equals(tipoAtributoS.REAL.toString()))){

                                tipohREM.append(tipoAtributoS.REAL.toString());
                        }
                         else if ((tipohEM.toString().equals(tipoAtributoS.ENT.toString()))
                                &&(tipoExpUn.toString().equals(tipoAtributoS.ENT.toString()))){

                                tipohREM.append(tipoAtributoS.ENT.toString());
                        }
                        else{
                            /*Si los tipos de los operandos no cuadran con
                             ninguna de las combinacion correctas posibles,
                             apuntamos el error y decimos que el tipo final de
                             la expresion es de tipo error.*/
                            if ((!tipohEM.toString().equals(tipoAtributoS.TERR.toString()))&&(!tipoExpUn.toString().equals(tipoAtributoS.TERR.toString()))){
                                errores.add("Error de tipos en la linea "+linea+" y en la columna "+columna);
                            }
                            tipohREM.append(tipoAtributoS.TERR.toString());
                        }
                }
                /*Si el operando de la expresion es de tipo AND.*/
                else if ((actual.getCat().toString()).equals(categoriaLexica.CLAND.toString())){
                        if ((tipohEM.toString().equals(tipoAtributoS.LOG.toString()))
                                &&(tipoExpUn.toString().equals(tipoAtributoS.LOG.toString()))){

                                tipohREM.append(tipoAtributoS.LOG.toString());
                        }
                        else{
                            /*Si los tipos de los operandos no cuadran con
                             ninguna de las combinacion correctas posibles,
                             apuntamos el error y decimos que el tipo final de
                             la expresion es de tipo error.*/
                            if ((!tipohEM.toString().equals(tipoAtributoS.TERR.toString()))&&(!tipoExpUn.toString().equals(tipoAtributoS.TERR.toString()))){
                                errores.add("Error de operador en la linea "+linea+" y en la columana "+columna+" porque ambas expresiones deben ser de tipo logicas");
                            }
                            tipohREM.append(tipoAtributoS.TERR.toString());
                        }
                }
                /*Si el operando de la expresion es de tipo modulo.*/
                else if ((actual.getCat().toString()).equals(categoriaLexica.CLMOD.toString())){
                        if ((tipohEM.toString().equals(tipoAtributoS.ENT.toString()))
                                &&(tipoExpUn.toString().equals(tipoAtributoS.ENT.toString()))){

                                tipohREM.append(tipoAtributoS.ENT.toString());
                        }
                        else{
                            /*Si los tipos de los operandos no cuadran con
                             ninguna de las combinacion correctas posibles,
                             apuntamos el error y decimos que el tipo final de
                             la expresion es de tipo error.*/
                            if ((!tipohEM.toString().equals(tipoAtributoS.TERR.toString()))&&(!tipoExpUn.toString().equals(tipoAtributoS.TERR.toString()))){
                                errores.add("Error de operador en la linea "+linea+" y en la columana "+columna+" porque ambas expresiones deben ser de tipo enteros");
                            }
                            tipohREM.append(tipoAtributoS.TERR.toString());

                        }
                }
                else{ 
                    /*Si el operador no fuera ninguo de los operadores validos.*/
                    tipohREM.append(tipoAtributoS.TERR.toString());
                }
                /*Aqui como marca la produccion de la gramatica puesta en la
                 cabecera de la funcion, necesitamos llamar recursivamente de
                 nuevo a reconoceRExpMult por si esta expresion de suma
                 estuviera formada por mas de dos operandos y mas de un
                 operador. Si no fuera asi, no pasa nada porque la recursion de
                 la expresion nos devolvera el mismo tipo obtenido hasta ahora y
                 lo mismo con el error.*/
                StringBuffer tipoREM1=new StringBuffer("");
                boolean errREM1 = reconoceRExpSum(errhREM,tipohREM,tipoREM1);
                /*Preparamos tanto el tipo como el error a devolver.*/
                tipoREM.append(tipoREM1);
                return errREM1;
        }
        else{
            /*Si el resto de la expresion no es de tipo multiplicacion (porque
             el token actual no es de OpSum) es porque en la recursion de la
             primera parte de la expresion ya se ha reconocido la expresion
             basica entera.*/
            tipoREM.append(tipohEM);
            return errhREM;
        }
    }
    private String reconoceOpMult(Token actual){

       String operador="";
       if((actual.getCat().toString()).equals(categoriaLexica.CLMULT.toString()))
           operador="MUL";
        else if((actual.getCat().toString()).equals(categoriaLexica.CLDIV.toString()))
            operador="DIV";
        else if((actual.getCat().toString()).equals(categoriaLexica.CLMOD.toString()))
            operador="MOD";
        else if((actual.getCat().toString()).equals(categoriaLexica.CLAND.toString()))
            operador="AND";
      return operador;
    }
/*******************************************************************************
 *                                                                             *
 * EXPRESION UNARIA                                                            *
 *                                                                             *
 *      ExpUn ::= OpUn ExpUn | OpCast Fact | Fact                              *
 *                                                                             *
 ******************************************************************************/
    private boolean reconoceExpUn(StringBuffer tipoExpUn){
        boolean errEU=false;
        Token actual=dameTokenActual();        
        /* Comprobamos si realmente se trata de una operacion unaria. Para ello,
         el token actual tendria que ser alguno de los operadores unarios
         siguientes.*/
        if ((actual.getCat().equals(Enumerados.categoriaLexica.CLRES))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLNEG))){
            /*Reconocemos el operador de la expresion.*/
            String operador=reconoceOpUn(actual);
            siguienteToken();
            /*Realizamos la recursion.*/
            StringBuffer tipoEU1=new StringBuffer("");
            boolean errEU1=reconoceExpUn(tipoEU1);
            /*Añadimos el codigo del operador correspondiente*/
            codigo.add(operador+"\n");
            /*Calculamos el tipo final de la expresion*/
            StringBuffer tipoEU = new StringBuffer("");
            if((actual.getCat().toString()).equals(categoriaLexica.CLNEG.toString())){
                    if ((tipoEU1.toString().equals(tipoAtributoS.ENT.toString()))){
                            tipoEU.append(tipoAtributoS.ENT.toString());
                    }
                    else{
                        /*Si el tipo del operando no cuadra con ninguna de las
                         combinacion correctas posibles, apuntamos el error y
                         decimos que el tipo final de la expresion es de tipo
                         error.*/
                        if(!tipoEU1.toString().equals(tipoAtributoS.TERR.toString())){
                            errores.add("Error de tipo en la linea "+linea+" y columna "+columna+" porque la expresion debe ser de tipo entero");
                        }
                        tipoEU.append(tipoAtributoS.TERR.toString());
                    }
            }
            /*El operador es cambio de signo (-)*/
            else if((actual.getCat().toString()).equals(categoriaLexica.CLRES.toString())){
                    if ((tipoEU1.toString().equals(tipoAtributoS.REAL.toString()))){
                            tipoEU.append(tipoAtributoS.REAL.toString());
                    }
                    else if((tipoEU1.toString().equals(tipoAtributoS.ENT.toString()))){
                            tipoEU.append(tipoAtributoS.ENT.toString());
                    }
                    else{
                        /*Si el tipo del operando no cuadra con ninguna de las
                         combinacion correctas posibles, apuntamos el error y
                         decimos que el tipo final de la expresion es de tipo
                         error.*/
                        if(!tipoEU1.toString().equals(tipoAtributoS.TERR.toString())){
                            errores.add("Error de tipo en la linea "+linea+" y columna "+columna+" porque la expresion debe ser de tipo entero o de tipo real");
                        }
                        tipoEU.append(tipoAtributoS.TERR.toString());}
            }
            /*Si el operador no fuera ninguo de los operadores validos.*/
            else tipoEU.append(tipoAtributoS.TERR.toString());
            /* Devolvemos el tipo de la Expresion unaria y la posibilidad de error*/
            tipoExpUn.append(tipoEU);
            return errEU1;
        }
        if ((actual.getCat().equals(Enumerados.categoriaLexica.CLCASTINT))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLCASTREAL))){

            /*Reconocemos el operador de la expresion.*/
            String operador=reconoceOpCast(actual);
            siguienteToken();
            /*Comenzamos el procesamiento de la segunda parte de la expresion.
             Este procesamiento es recursivo ya que esta segunda parte puede ser
             una expresion basica completa.*/
            StringBuffer tipoF=new StringBuffer("");
            boolean errF=reconoceFactor(tipoF);
            /*Introducimos el codigo del operador necesario para el
             funcionamiento de la maquina p*/
            codigo.add(operador+"\n");
            /*Devolvemos si ha existido error en la expresion unaria que
             realmente sera un error detectado en la recursion del procesamiento
             de la segunda parte de la expresion (Fact).*/
            errEU=errF;
            /*Calculamos el tipo de la expresion completa a devolver.*/
            StringBuffer tipoEU = new StringBuffer("");
            /*El operador es un casting a enteros.*/
            if((actual.getCat().toString()).equals(categoriaLexica.CLCASTINT.toString())){
                    if ((tipoF.toString().equals(tipoAtributoS.REAL.toString()))){
                            tipoEU.append(tipoAtributoS.ENT.toString());
                    }
                    else if((tipoF.toString().equals(tipoAtributoS.ENT.toString()))){
                            tipoEU.append(tipoAtributoS.ENT.toString());
                    }
                    else{
                        /*Si el tipo del operando no cuadra con ninguna de las
                         combinacion correctas posibles, apuntamos el error y
                         decimos que el tipo final de la expresion es de tipo
                         error.*/
                        if(!tipoF.toString().equals(tipoAtributoS.TERR.toString())){
                            errores.add("Error de tipo en la linea "+linea+" y columna "+columna+" porque la expresion debe ser de tipo entero o de tipo real");
                        }
                        tipoEU.append(tipoAtributoS.TERR.toString());
                    }
            }
            /*El operador es un casting a reales.*/
            else if((actual.getCat().toString()).equals(categoriaLexica.CLCASTREAL.toString())){
                    if ((tipoF.toString().equals(tipoAtributoS.REAL.toString()))){
                            tipoEU.append(tipoAtributoS.REAL.toString());
                    }
                    else if((tipoF.toString().equals(tipoAtributoS.ENT.toString()))){
                            tipoEU.append(tipoAtributoS.REAL.toString());
                    }
                    else{
                        /*Si el tipo del operando no cuadra con ninguna de las
                         combinacion correctas posibles, apuntamos el error y
                         decimos que el tipo final de la expresion es de tipo
                         error.*/
                        if(!tipoF.toString().equals(tipoAtributoS.TERR.toString())){
                            errores.add("Error de tipo en la linea "+linea+" y columna "+columna+" porque la expresion debe ser de tipo entero o de tipo real");
                        }
                        tipoEU.append(tipoAtributoS.TERR.toString());
                    }
            }
            /*Si el operador no fuera ninguo de los operadores validos.*/
            else tipoEU.append(tipoAtributoS.TERR.toString());
        /* Devolvemos el tipo de la Expresion unaria y la posibilidad de error*/
        tipoExpUn.append(tipoEU);
        return errEU;
        }
        /*Si llegamos hasta aqui es porque el token actual es un literal o
         factor (es decir, como veremos a continuacion, un IDENT, un entero,
         un real o un parentesis. De ser un parentesis, este nos hara
         recursivamente tener que procesar una nueva expresion o expresion
         basica)*/
        else{
            boolean errF;
            StringBuffer tipoF=new StringBuffer("");
            /* reconocemos el factor*/
            errF=reconoceFactor(tipoF);
            /* Devolvemos el tipo de la expresion, que en este caso es el tipo
             del factor, y la posibilidad de que haya sucedido algun error. En
             este caso tambien ha tenido que producirse en el procesamiento del
             factor.*/
            errEU=errF;
            tipoExpUn.append(tipoF);
            return errEU;
        }
    }

    private String reconoceOpUn(Token actual){
        String operador="";
        if((actual.getCat().toString()).equals(categoriaLexica.CLNEG.toString()))
           operador="NEG";
        else if((actual.getCat().toString()).equals(categoriaLexica.CLRES.toString()))
            operador="CS";
        return operador;
    }
    private String reconoceOpCast(Token actual){
        String operador="";
        if((actual.getCat().toString()).equals(categoriaLexica.CLCASTINT.toString()))
            operador="CASTING_E";
        else if((actual.getCat().toString()).equals(categoriaLexica.CLCASTREAL.toString()))
           operador="CASTING_R";
        return operador;
    }

/*******************************************************************************
 *                                                                             *
 * FACTOR                                                                      *
 *                                                                             *
 *      Fact ::= IDENT | NUMENT | NUMREAL | (Exp) // (ExpBasica) => Es asi en  *
 *      en la implementacion ya que en la gramtica solo se hace recursion sobre*
 *      Exp.                                                                   *
 *                                                                             *
 ******************************************************************************/
    private boolean reconoceFactor(StringBuffer tipoF){
        boolean errF=false;
        Token actual=dameTokenActual();        
        /* Si el token leido es un token erroneo*/
        if(actual.getCat().equals(Enumerados.categoriaLexica.CLERROR)){
            errF=false;
            errores.add("Token erroneo en la linea "+linea+" y columna "+columna);
            tipoF.append("TERR");
        }
        /* Si el token es un numero real.*/
        else if((actual.getCat().equals(Enumerados.categoriaLexica.CLREAL))){
            codigo.add("apila "+actual.getLex()+" 1\n");
            errF=false;
            tipoF.append("REAL");
        }
        /* Si el token es un numero entero.*/
        else if (actual.getCat().equals(Enumerados.categoriaLexica.CLENT)){
            codigo.add("apila "+actual.getLex()+" 0\n");
            errF=false;
            tipoF.append("ENT");
        }
        /* Si el token es un identificador*/
        else if (actual.getCat().equals(Enumerados.categoriaLexica.CLIDENT)){
            /*Comprobamos que este identificador haya sido declarado previamente
             en la seccion de declaraciones. Para ello, comprobamos que el token
             este en la tabla de simbolos construida durante el procesamiento
             de la seccion de declaraciones.*/
            if(ts.estaID(actual.getLex())){
                codigo.add("apila_dir "+ts.getDir(actual.getLex())+"\n");
                errF=false;
                tipoF.append(ts.getTipo(actual.getLex()));
            }
            else{
                /* El identificador no ha sido declarado previamente.*/
                errores.add("Error, el identificador de la linea "+linea+" y columna "+columna+" no ha sido declarado previamente.");
                errF=true;
                tipoF.append("TERR");
            }
        }
        /* Si el token actual es IN o OUT tenemos que reconocer esta nueva
         expresion de forma recursiva llamando a reconoceExp.*/
        else if (actual.getCat().equals(Enumerados.categoriaLexica.CLIN)
                ||actual.getCat().equals(Enumerados.categoriaLexica.CLOUT)){
            
            StringBuffer tipoIExp=new StringBuffer("");
            boolean errIExp=false;

            /* Reconocemos o procesamos la expresion.*/
            errIExp=reconoceIExp(tipoIExp);
            codigo.add("duplicar\n");
            /* El tipo del factor sera el tipo de la nueva expresion reconocida
             y devolveremos un error en funcion de si se ha producido alguno en
             el procesamiento de la nueva expresion.*/
            tipoF.append(tipoIExp);
            errF=errIExp;
        }
        /* Si el token actual es un parentesis abierto tendremos que comprobar
         el siguiente token. En funcion de este, tendremos que procesar
         recursivamente una nueva expresion o expresion basica.*/
        else if (actual.getCat().equals(Enumerados.categoriaLexica.CLPARAB)){
            siguienteToken();
            
            StringBuffer tipoIExp=new StringBuffer("");
            boolean errIExp=false;
         
            actual = dameTokenActual();
            /* Reconocemos o procesamos la expresion*/
            errIExp=reconoceIExp(tipoIExp);
            codigo.add("duplicar\n");
            /* El tipo del factor sera el tipo de la nueva expresion reconocida
             y devolveremos un error en funcion de si se ha producido alguno en
             el procesamiento de la nueva expresion.*/
            tipoF.append(tipoIExp);
            errF=errIExp;

            /*Actualizamos el token para comprobar si es parentesis cerrado*/
            actual=dameTokenActual();
            /* Si no encontramos un parentesis cerrado producimos un error.*/
            if(!(actual.getCat().equals(Enumerados.categoriaLexica.CLPARCER))){
                errores.add("Error sintactico incontextual en la linea "+linea +" y columna "+columna+". Se esperaba un token de tipo paréntesis cerrado");
                return true;
            }
            siguienteToken();
            return errF;
        }
    else{
            errores.add("Error sintactico incontextual en la linea "+linea +" y columna "+columna+". Lugar incorrecto del token reconocido");
            return true;
    }
    actual=dameTokenActual();
    if(!(actual.getCat().equals(Enumerados.categoriaLexica.CLPYC)))
        siguienteToken();
    return errF;
    }

/*******************************************************************************
 *                                                                             *
 * FUNCIONES AUXILIARES                                                        *
 *                                                                             *
 ******************************************************************************/
    
    private void siguienteToken(){tokenActual++;columna++;}
    private Token dameTokenActual(){return (Token) tokens.get(tokenActual);}

}
